{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 如何使用LangChain插件\n",
    "\n",
    "为了便利大家结合文心大模型与[LangChain](https://www.langchain.com/)开发应用，ERNIE Bot Agent扩展LangChain框架的功能，提供大语言模型（large language model）、聊天模型（chat model）、文本嵌入模型（text embedding model）等组件（这些组件的集合称为LangChain插件）。本文档将介绍ERNIE Bot Agent的LangChain插件的基础用法。\n",
    "\n",
    "ERNIE Bot Agent的LangChain插件目前包含如下组件：\n",
    "\n",
    "- `ErnieBot`：大语言模型，用于完成文本补全任务。\n",
    "- `ErnieBotChat`：聊天模型，用于完成对话补全任务。\n",
    "- `ErnieEmbeddings`：文本嵌入模型，用于生成文本的向量表示。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备工作\n",
    "\n",
    "安装`erniebot-agent`与`langchain`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install erniebot-agent langchain"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据[ERNIE Bot 认证鉴权文档](https://github.com/PaddlePaddle/ERNIE-SDK/blob/develop/docs/authentication.md)中的说明，获取AI Studio星河社区的access token。执行如下代码，填写access token并敲击回车键："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import getpass\n",
    "\n",
    "access_token = getpass.getpass(prompt=\"Access token: \")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `ErnieBot`\n",
    "\n",
    "`ErnieBot`是LangChain大语言模型组件，可用于完成文本补全任务。本文档仅介绍`ErnieBot`的用法，大家可以在[LangChain官方文档](https://python.langchain.com/docs/modules/model_io/llms/)了解关于大语言模型组件的更多信息。\n",
    "\n",
    "创建一个`ErnieBot`对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from erniebot_agent.extensions.langchain.llms import ErnieBot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = ErnieBot(aistudio_access_token=access_token)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基本使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "question = \"What does SFINAE mean in C++ template metaprogramming?\"\n",
    "\n",
    "print(llm(question))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在chain中使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.chains import LLMChain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = \"Tell me a joke about {content}.\"\n",
    "\n",
    "prompt = PromptTemplate(template=template, input_variables=[\"content\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm_chain = LLMChain(prompt=prompt, llm=llm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "content = \"rabbits\"\n",
    "\n",
    "print(llm_chain.run(content=content))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 异步调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "question = \"Please write a Python program that checks if an integer is a prime number.\"\n",
    "\n",
    "answer = await llm.agenerate([question])\n",
    "print(answer)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 流式回复"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "question = \"What is the difference between capybara and kiwi?\"\n",
    "\n",
    "for chunk in llm.stream(question):\n",
    "    print(chunk, end=\"\", flush=True)\n",
    "print(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `ErnieBotChat`\n",
    "\n",
    "`ErnieBotChat`是LangChain聊天模型组件，可用于完成文本补全任务。本文档仅介绍`ErnieBotChat`的用法，大家可以在[LangChain官方文档](https://python.langchain.com/docs/modules/model_io/chat/)了解关于聊天模型模型组件的更多信息。\n",
    "\n",
    "创建一个`ErnieBotChat`对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from erniebot_agent.extensions.langchain.chat_models import ErnieBotChat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chat = ErnieBotChat(aistudio_access_token=access_token)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 基本使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models.base import HumanMessage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = HumanMessage(content=\"What does SFINAE mean in C++ template metaprogramming?\")\n",
    "print(chat([message]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在chain中使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = \"Tell me a joke about {content}.\"\n",
    "prompt = ChatPromptTemplate.from_messages([(\"human\", message)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = prompt | chat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(chain.invoke({\"content\": \"rabbits\"}))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 异步调用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models.base import HumanMessage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = HumanMessage(content=\"Please write a Python program that checks if an integer is a prime number.\")\n",
    "\n",
    "response = await chat.agenerate([[message]])\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 流式回复"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chat_models.base import HumanMessage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = HumanMessage(content=\"What is the difference between capybara and kiwi?\")\n",
    "\n",
    "for chunk in chat.stream([message]):\n",
    "    print(chunk.content, end=\"\", flush=True)\n",
    "print(\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## `ErnieEmbeddings`\n",
    "\n",
    "`ErnieEmbeddings`是LangChain文本嵌入模型组件，可用于生成文本的向量表示。本文档仅介绍`ErnieEmbeddings`的用法，大家可以在[LangChain官方文档](https://python.langchain.com/docs/modules/data_connection/text_embedding/)了解关于聊天模型模型组件的更多信息。\n",
    "\n",
    "创建一个`ErnieEmbeddings`对象："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from erniebot_agent.extensions.langchain.embeddings import ErnieEmbeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "embeddings = ErnieEmbeddings(aistudio_access_token=access_token)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 处理单段输入文本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "text = \"This is a test document.\"\n",
    "\n",
    "query_result = embeddings.embed_query(text)\n",
    "print(len(query_result))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 处理多段输入文本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "texts = [\"doc1\", \"doc2\"]\n",
    "\n",
    "docs_result = embeddings.embed_documents(texts)\n",
    "print(len(docs_result))\n",
    "for res in docs_result:\n",
    "    print(len(res))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
